package edu.xhu.test.oss.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;

import edu.xhu.test.oss.config.BiliOssConfigProperties;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
@Component
@EnableConfigurationProperties({BiliOssConfigProperties.class})
public class BiliOssUtils {


    //已经内置好分片桶，正式桶
    private final BiliOssConfigProperties biliOssConfigProperties;


    /**
     * @param objectName 图片名
     * @param file       图片文件流
     * @return 图片的URL，如果为空，说明上传失败
     */
    public String uploadImageFile(@NonNull String objectName, @NonNull MultipartFile file) {
        //图片的URL
        String imageUrl = null;
        //桶路径
        String bucketName = biliOssConfigProperties.getImageBucket();
        String fileName = getFileName(objectName);
        imageUrl=biliOssConfigProperties.getImageBucketUrl()+fileName;
        //建立连接
        OSS ossClient=new OSSClient(biliOssConfigProperties.getEndpoints(),biliOssConfigProperties.getAccessKey(),biliOssConfigProperties.getSecretKey());
        if(ossClient!=null){
            try {
                //上传图片
                ossClient.putObject(bucketName, fileName, file.getInputStream());
                return imageUrl;
            } catch (IOException e) {
                log.error("图片上传失败!|参数：bucketName:{},originalFilename:{}|异常:{}", bucketName, objectName, e);
                return imageUrl;
            }
        }
        return imageUrl;
    }
    private String getFileName(String objectName){
        String ext = "." + FilenameUtils.getExtension(objectName);    // 获取文件后缀
        String uuid = System.currentTimeMillis() + UUID.randomUUID().toString().replace("-", "");
        String fileName = uuid + ext;
        return fileName;
    }

//
//    /**
//     * 文件分块上传
//     *
//     * @param objectName 对象名称-视频的md5
//     * @param chunkIndex 分片索引
//     * @param file       文件
//     */
//    public Boolean uploadChunk(String objectName, Integer chunkIndex, MultipartFile file) {
//        //根据视频的md5从redis中获取该视频的存储地址（ip地址）
//        String host = redisTemplate.opsForValue().get(objectName);
//
//        //redis中未保存该视频的存储位置
//        if (host == null) {
//            String hostToSet = this.findServerWithMaxDiskSpaceIP();
//
//            if (hostToSet == null)
//                return false;
//
//            boolean isSetSuccessful = redisTemplate.opsForValue().setIfAbsent(objectName, hostToSet);
//
//            if (isSetSuccessful)
//                host = hostToSet;
//            else
//                host = redisTemplate.opsForValue().get(objectName);
//        }
//
//        if (host != null) {
//            try {
//                if (chunkIndex != null) {
//                    objectName = objectName.concat("/").concat(Integer.toString(chunkIndex));
//                }
//
//                MinioClient minioClient = biliMinIOClientMap.get(host).getMinioClient();
//                String chunkBucketName = biliMinIOConfigProperties.getChunkBucket();
//
//                // 写入文件
//                minioClient.putObject(PutObjectArgs.builder()
//                        .bucket(chunkBucketName)
//                        .object(objectName)
//                        .stream(file.getInputStream(), file.getSize(), -1)
//                        .contentType(file.getContentType())
//                        .build());
//
//                log.debug("上传到minio文件|uploadFile|参数：chunkBucketName：{}，objectName：{}，chunkIndex：{}"
//                        , chunkBucketName, objectName, chunkIndex);
//
//                return true;
//            } catch (Exception e) {
//                log.error("文件上传到Minio异常|参数：chunkBucketName:{},objectName:{},chunkIndex:{}|异常:{}", biliMinIOConfigProperties.getChunkBucket(), objectName, chunkIndex, e);
//                return false;
//            }
//        }
//        return false;
//    }
//
//    /**
//     * 文件分块合并，已经内置好分片桶，正式桶
//     *
//     * @param objectName 正式桶中的目录路径
//     * @param md5        视频的 md5 码
//     * @return 返回视频URL，返回如果为空，说明合并分片失败
//     */
//    public String composeChunks(String objectName, String md5) {
//        //视频URL
//        String videoUrl = null;
//
//        MinioClient minioClient = null;
//
//        // 计算视频已经上传成功的分片数量
//        int chunkCount = this.countChunksOfVideo(md5);
//
//        //根据视频的md5从redis中获取该视频的存储地址（ip地址）
//        String host = redisTemplate.opsForValue().get(md5);
//
//        if (host != null)
//            minioClient = biliMinIOClientMap.get(host).getMinioClient();
//
//        if (chunkCount > 0 && minioClient != null) {
//            String bucketName = biliMinIOConfigProperties.getBucket(); //正式桶
//            String chunkBucketName = biliMinIOConfigProperties.getChunkBucket(); //分片桶
//
//            //从分片缓存目录获取所有分片
//            List<ComposeSource> sourceObjectList = Stream.iterate(0, i -> ++i)
//                    .limit(chunkCount)  //分片数量
//                    .map(i -> ComposeSource.builder()
//                            .bucket(chunkBucketName) //分片存储桶名称
//                            .object(md5.concat("/").concat(Integer.toString(i)))
//                            .build())
//                    .collect(Collectors.toList());
//
//            //开始合并分片
//            try {
//                ObjectWriteResponse response = minioClient.composeObject(
//                        ComposeObjectArgs.builder()
//                                .bucket(bucketName)
//                                .object(objectName)
//                                .sources(sourceObjectList)
//                                .build());
//            } catch (Exception e) {
//                log.error("Minio文件按合并异常!|参数：bucketName:{},objectName:{}|异常:{}", bucketName, objectName, e);
//                return videoUrl;
//            }
//
//            //清理该视频所有缓存的临时分片文件
//            this.removeTemporaryChunks(md5);
//
//            //清理redis中的缓存
//            redisTemplate.delete(md5);
//
//
//            //拼接视频URL
//            videoUrl = biliMinIOClientMap.get(host).getReadRootPath()
//                    .concat("/")
//                    .concat(bucketName)
//                    .concat("/")
//                    .concat(objectName);
//
//            return videoUrl;
//        }
//
//        return videoUrl;
//    }
//
//    /**
//     * 删除某个视频所有缓存的分片文件
//     *
//     * @param prefixObjectName 视频的md5码
//     */
//    public void removeTemporaryChunks(String prefixObjectName) {
//        MinioClient minioClient = null;
//
//        String chunkBucketName = biliMinIOConfigProperties.getChunkBucket(); //分片桶
//
//        //根据视频的md5从redis中获取该视频的存储地址（ip地址）
//        String host = redisTemplate.opsForValue().get(prefixObjectName);
//
//        if (host != null)
//            minioClient = biliMinIOClientMap.get(host).getMinioClient();
//
//        if (minioClient != null) {
//            try {
//                Iterable<Result<Item>> objects = minioClient.listObjects(
//                        ListObjectsArgs.builder()
//                                .bucket(chunkBucketName)
//                                .prefix(prefixObjectName.concat("/"))
//                                .recursive(true)
//                                .build());
//
//                //拿到该视频所有缓存分片的路径
//                List<String> objectsToDelete = new ArrayList<>();
//                for (Result<Item> result : objects) {
//                    Item item = result.get();
//                    objectsToDelete.add(item.objectName());
//                }
//
//                //遍历路径，删除该视频所有缓存的分片
//                for (String objectName : objectsToDelete) {
//                    minioClient.removeObject(
//                            RemoveObjectArgs.builder()
//                                    .bucket(chunkBucketName)
//                                    .object(objectName)
//                                    .build());
//                }
//            } catch (Exception e) {
//                log.error(e.getMessage());
//            }
//        }
//    }
//
//    /**
//     * 计算视频已经上传成功的分块数量
//     *
//     * @param prefixObjectName 视频的 md5
//     * @return 上传成功的分片数量，返回-1表示异常
//     */
//    public Integer countChunksOfVideo(String prefixObjectName) {
//        //根据视频的md5从redis中获取该视频的存储地址（ip地址）
//        String host = redisTemplate.opsForValue().get(prefixObjectName);
//
//        if (host == null)
//            return -1;
//
//        MinioClient minioClient = biliMinIOClientMap.get(host).getMinioClient();
//
//        if (minioClient != null) {
//            String chunkBucketName = biliMinIOConfigProperties.getChunkBucket();
//            try {
//                Iterable<Result<Item>> results = minioClient.listObjects(
//                        ListObjectsArgs.builder()
//                                .bucket(chunkBucketName)
//                                .prefix(prefixObjectName.concat("/"))
//                                .build());
//
//                int chunkCount = 0;
//
//                for (Result<Item> result : results) {
//                    Item item = result.get();
//                    if (!item.isDir()) {
//                        chunkCount++;
//                    }
//                }
//
//                return chunkCount;
//
//            } catch (Exception e) {
//                log.error("Minio获取文件流异常!|参数：chunkBucketName:{},prefixObjectName:{}|异常:{}", chunkBucketName, prefixObjectName, e);
//            }
//        }
//
//        return -1;
//    }
//
//
//    /**
//     * @return 剩余磁盘空间最大的服务器ip地址，返回空说明获取失败
//     */
//    public String findServerWithMaxDiskSpaceIP() {
//        String maxDiskSpaceServerIP = null;
//        double maxDiskSpace = -1;
//
//
//        for (Map.Entry<String, BiliOssClient> entry : biliMinIOClientMap.entrySet()) {
//            //判断SSH连接是否已经失效
//            if (!entry.getValue().getBiliSSHCilent().isConnected())
//                entry.getValue().getBiliSSHCilent().connect();
//
//            if (entry.getValue().getBiliSSHCilent().getAvailableDiskSpaceInGB() > maxDiskSpace && entry.getValue().getBiliSSHCilent().isConnected()) {
//                maxDiskSpace = entry.getValue().getBiliSSHCilent().getAvailableDiskSpaceInGB();
//                maxDiskSpaceServerIP = entry.getValue().getBiliSSHCilent().getHost();
//            }
//        }
//        return maxDiskSpaceServerIP;
//    }
//
//    /**
//     * 测试方法
//     */
//    public void helloBiliMinioUtils() {
//        // 使用for-each循环遍历values
//        for (BiliOssClient value : biliMinIOClientMap.values()) {
//            System.out.println("session: " + value.getBiliSSHCilent().isConnected());
//            System.out.println("host: " + value.getBiliSSHCilent().getHost());
//            System.out.println("磁盘剩余空间: " + value.getBiliSSHCilent().getAvailableDiskSpaceInGB() + "GB");
//            System.out.println();
//        }
//
//        // 使用for-each循环遍历keySet
//        for (String key : biliMinIOClientMap.keySet()) {
//            System.out.println("key: " + key);
//            System.out.println("host: " + biliMinIOClientMap.get(key).getBiliSSHCilent().getHost());
//        }
//    }
}
